home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / nfs / nfswatch4.0 / @ next >
Encoding:
Internet Message Format  |  1993-03-01  |  20.6 KB

  1. Return-Path: mogul@pa.dec.com
  2. Received: from bank.ecn.purdue.edu by harbor.ecn.purdue.edu (5.65/1.32jrs)
  3.     id AA24638; Mon, 1 Mar 93 14:37:48 -0500
  4. Received: from inet-gw-2.pa.dec.com by bank.ecn.purdue.edu (5.65/1.32jrs)
  5.     id AA19147; Mon, 1 Mar 93 14:37:41 -0500
  6. Received: by inet-gw-2.pa.dec.com; id AA07016; Mon, 1 Mar 93 11:37:39 -0800
  7. Received: by acetes.pa.dec.com; id AA20664; Mon, 1 Mar 93 11:37:38 -0800
  8. Message-Id: <9303011937.AA20664@acetes.pa.dec.com>
  9. To: "David A. Curry" <davy@ecn.purdue.edu>
  10. Subject: Re: NFSWATCH 4.0 beta (new stuff) 
  11. In-Reply-To: Your message of "Wed, 24 Feb 93 12:43:45 EST."
  12.              <9302241743.AA24041@intrepid.ecn.purdue.edu> 
  13. Date: Mon, 01 Mar 93 11:37:37 PST
  14. From: Jeffrey Mogul <mogul@pa.dec.com>
  15.  
  16. I found a few byte-order bugs, and there might well be more.
  17. (1) In CountCallAuth(), the oauth[] is in non-native order.
  18. The most obvious consequence of getting this wrong is a core
  19. dump (the value of the "len" variable becomes enormous) and
  20. it seems necessary also to byteswap the value of the auth
  21. variable before looking up a uid.
  22.  
  23. (2) nfs_hash_reply() needs to put the rm_xid into native order.
  24. Someone already does this before nfs_hash_call() gets its fingers
  25. on the rm_xid field (probably the xdr routines) and the xids
  26. weren't matching up.
  27.  
  28. I've appended my revised copy of rpcfilter.c
  29.  
  30. -Jeff
  31.  
  32. #ifndef lint
  33. static char *RCSid = "$Header: /home/harbor/davy/system/nfswatch/RCS/rpcfilter.c,v 3.5 1993/01/16 19:08:59 davy Exp davy $";
  34. #endif
  35.  
  36. #include "os.h"
  37.  
  38. /*
  39.  * rpcfilter.c - filter RPC packets.
  40.  *
  41.  * David A. Curry                Jeffrey C. Mogul
  42.  * Purdue University                Digital Equipment Corporation
  43.  * Engineering Computer Network            Western Research Laboratory
  44.  * 1285 Electrical Engineering Building        250 University Avenue
  45.  * West Lafayette, IN 47907-1285        Palo Alto, CA 94301
  46.  * davy@ecn.purdue.edu                mogul@decwrl.dec.com
  47.  *
  48.  * $Log: rpcfilter.c,v $
  49.  * Revision 3.5  1993/01/16  19:08:59  davy
  50.  * Corrected Jeff's address.
  51.  *
  52.  * Revision 3.4  1993/01/15  19:33:39  davy
  53.  * Miscellaneous cleanups.
  54.  *
  55.  * Revision 3.3  1993/01/15  15:43:36  davy
  56.  * Assorted changes for porting to Solaris 2.x/SVR4.
  57.  *
  58.  * Revision 3.2  1993/01/13  20:18:17  davy
  59.  * Put in OS-specific define scheme, and merged in Tim Hudson's code for
  60.  * SGI systems (as yet untested).
  61.  *
  62.  * Revision 3.1  1993/01/13  13:50:59  davy
  63.  * Made the file matching code work on Sun-3's, and also put a generic one in
  64.  * there in hopes it'll work.
  65.  *
  66.  * Revision 3.0  1991/01/23  08:23:20  davy
  67.  * NFSWATCH Version 3.0.
  68.  *
  69.  * Revision 1.5  91/01/17  10:13:02  davy
  70.  * Bug fix from Jeff Mogul.
  71.  * 
  72.  * Revision 1.7  91/01/16  15:49:12  mogul
  73.  * Print server or client address in a.b.c.d notation if name not known
  74.  * 
  75.  * Revision 1.6  91/01/07  15:35:51  mogul
  76.  * Uses hash table instead of linear search on clients
  77.  * One-element "hint" cache to avoid client hash lookup
  78.  * 
  79.  * Revision 1.5  91/01/04  14:12:35  mogul
  80.  * Support for client counters
  81.  * Disable screen update during database upheaval
  82.  * 
  83.  * Revision 1.4  91/01/03  17:35:00  mogul
  84.  * Count per-procedure info
  85.  * 
  86.  * Revision 1.3  90/12/04  08:22:06  davy
  87.  * Fix from Dan Trinkle (trinkle@cs.purdue.edu) to determine byte order in
  88.  * file handle.
  89.  * 
  90.  * Revision 1.2  90/08/17  15:47:44  davy
  91.  * NFSWATCH Version 2.0.
  92.  * 
  93.  * Revision 1.1  88/11/29  11:20:51  davy
  94.  * NFSWATCH Release 1.0
  95.  * 
  96.  */
  97. #include <sys/param.h>
  98. #include <sys/socket.h>
  99. #include <netinet/in.h>
  100. #include <sys/stat.h>
  101. #ifdef SVR4
  102. #include <sys/tiuser.h>
  103. #include <sys/sysmacros.h>
  104. #endif
  105. #include <rpc/types.h>
  106. #include <rpc/xdr.h>
  107. #include <rpc/auth.h>
  108. #include <rpc/clnt.h>
  109. #include <rpc/rpc_msg.h>
  110. #include <rpc/pmap_clnt.h>
  111. #include <rpc/svc.h>
  112. #include <netdb.h>
  113. #include <errno.h>
  114. #include <stdio.h>
  115. #include <signal.h>
  116. #include <math.h>
  117. #include <pwd.h>
  118.  
  119. #define NFSSERVER    1
  120.  
  121. #ifdef sun
  122. #include <sys/vfs.h>
  123. #include <nfs/nfs.h>
  124. #endif
  125. #ifdef ultrix
  126. #include <sys/types.h>
  127. #include <sys/time.h>
  128. #include <nfs/nfs.h>
  129. #endif
  130. #ifdef sgi
  131. #include <sys/time.h>
  132. #include "sgi.map.h"
  133. #include <sys/sysmacros.h>
  134. #endif
  135.  
  136. #include "nfswatch.h"
  137. #include "externs.h"
  138. #include "rpcdefs.h"
  139.  
  140. /*
  141.  * NFS procedure types and XDR argument decoding routines.
  142.  */
  143. static struct nfs_proc nfs_procs[] = {
  144. /* RFS_NULL (0)        */
  145.     NFS_READ,    xdr_void,    0,
  146. /* RFS_GETATTR (1)    */
  147.     NFS_READ,    xdr_fhandle,    sizeof(fhandle_t),
  148. /* RFS_SETATTR (2)    */
  149.     NFS_WRITE,    xdr_saargs,    sizeof(struct nfssaargs),
  150. /* RFS_ROOT (3)        */
  151.     NFS_READ,    xdr_void,    0,
  152. /* RFS_LOOKUP (4)    */
  153.     NFS_READ,    xdr_diropargs,    sizeof(struct nfsdiropargs),
  154. /* RFS_READLINK (5)    */
  155.     NFS_READ,    xdr_fhandle,    sizeof(fhandle_t),
  156. /* RFS_READ (6)        */
  157.     NFS_READ,    xdr_readargs,    sizeof(struct nfsreadargs),
  158. /* RFS_WRITECACHE (7)    */
  159.     NFS_WRITE,    xdr_void,    0,
  160. /* RFS_WRITE (8)    */
  161.     NFS_WRITE,    xdr_writeargs,    sizeof(struct nfswriteargs),
  162. /* RFS_CREATE (9)    */
  163.     NFS_WRITE,    xdr_creatargs,    sizeof(struct nfscreatargs),
  164. /* RFS_REMOVE (10)    */
  165.     NFS_WRITE,    xdr_diropargs,    sizeof(struct nfsdiropargs),
  166. /* RFS_RENAME (11)    */
  167.     NFS_WRITE,    xdr_rnmargs,    sizeof(struct nfsrnmargs),
  168. /* RFS_LINK (12)    */
  169.     NFS_WRITE,    xdr_linkargs,    sizeof(struct nfslinkargs),
  170. /* RFS_SYMLINK (13)    */
  171.     NFS_WRITE,    xdr_slargs,    sizeof(struct nfsslargs),
  172. /* RFS_MKDIR (14)    */
  173.     NFS_WRITE,    xdr_creatargs,    sizeof(struct nfscreatargs),
  174. /* RFS_RMDIR (15)    */
  175.     NFS_WRITE,    xdr_diropargs,    sizeof(struct nfsdiropargs),
  176. /* RFS_READDIR (16)    */
  177.     NFS_READ,    xdr_rddirargs,    sizeof(struct nfsrddirargs),
  178. /* RFS_STATFS (17)    */
  179.     NFS_READ,    xdr_fhandle,    sizeof(fhandle_t)
  180. };
  181.  
  182. NFSCall nfs_calls[NFSCALLHASHSIZE];
  183.  
  184. /*
  185.  * rpc_filter - pass off RPC packets to other filters.
  186.  */
  187. void
  188. rpc_filter(data, length, src, dst, tstamp)
  189. register u_long src, dst;
  190. struct timeval *tstamp;
  191. register u_int length;
  192. register char *data;
  193. {
  194.     register struct rpc_msg *msg;
  195.  
  196.     msg = (struct rpc_msg *) data;
  197.  
  198.     /*
  199.      * See which "direction" the packet is going.  We
  200.      * can classify RPC CALLs, but we cannot classify
  201.      * REPLYs, since they no longer have the RPC
  202.      * program number in them (sigh).
  203.      */
  204.     switch (ntohl(msg->rm_direction)) {
  205.     case CALL:            /* RPC call            */
  206.         rpc_callfilter(data, length, src, dst, tstamp);
  207.         break;
  208.     case REPLY:            /* RPC reply            */
  209.         rpc_replyfilter(data, length, src, dst, tstamp);
  210.         break;
  211.     default:            /* probably not an RPC packet    */
  212.         break;
  213.     }
  214. }
  215.  
  216. /*
  217.  * rpc_callfilter - filter RPC call packets.
  218.  */
  219. void
  220. rpc_callfilter(data, length, src, dst, tstamp)
  221. register u_long src, dst;
  222. struct timeval *tstamp;
  223. register u_int length;
  224. register char *data;
  225. {
  226.     register struct rpc_msg *msg;
  227.  
  228.     msg = (struct rpc_msg *) data;
  229.  
  230.     /*
  231.      * Decide what to do based on the program.
  232.      */
  233.     switch (ntohl(msg->rm_call.cb_prog)) {
  234.     case RPC_NFSPROG:
  235.         nfs_filter(data, length, src, dst, tstamp);
  236.         break;
  237.     case RPC_YPPROG:
  238.     case RPC_YPBINDPROG:
  239.     case RPC_YPPASSWDPROG:
  240.     case RPC_YPUPDATEPROG:
  241.     case RPC_CACHEPROG:
  242.     case RPC_CB_PROG:
  243.         pkt_counters[PKT_YELLOWPAGES].pc_interval++;
  244.         pkt_counters[PKT_YELLOWPAGES].pc_total++;
  245.         break;
  246.     case RPC_MOUNTPROG:
  247.         pkt_counters[PKT_NFSMOUNT].pc_interval++;
  248.         pkt_counters[PKT_NFSMOUNT].pc_total++;
  249.         break;
  250. #ifdef notdef
  251.     case RPC_PMAPPROG:
  252.     case RPC_RSTATPROG:
  253.     case RPC_RUSERSPROG:
  254.     case RPC_DBXPROG:
  255.     case RPC_WALLPROG:
  256.     case RPC_ETHERSTATPROG:
  257.     case RPC_RQUOTAPROG:
  258.     case RPC_SPRAYPROG:
  259.     case RPC_IBM3270PROG:
  260.     case RPC_IBMRJEPROG:
  261.     case RPC_SELNSVCPROG:
  262.     case RPC_RDATABASEPROG:
  263.     case RPC_REXECPROG:
  264.     case RPC_ALICEPROG:
  265.     case RPC_SCHEDPROG:
  266.     case RPC_LOCKPROG:
  267.     case RPC_NETLOCKPROG:
  268.     case RPC_X25PROG:
  269.     case RPC_STATMON1PROG:
  270.     case RPC_STATMON2PROG:
  271.     case RPC_SELNLIBPROG:
  272.     case RPC_BOOTPARAMPROG:
  273.     case RPC_MAZEPROG:
  274.     case RPC_KEYSERVEPROG:
  275.     case RPC_SECURECMDPROG:
  276.     case RPC_NETFWDIPROG:
  277.     case RPC_NETFWDTPROG:
  278.     case RPC_SUNLINKMAP_PROG:
  279.     case RPC_NETMONPROG:
  280.     case RPC_DBASEPROG:
  281.     case RPC_PWDAUTHPROG:
  282.     case RPC_TFSPROG:
  283.     case RPC_NSEPROG:
  284.     case RPC_NSE_ACTIVATE_PROG:
  285.     case RPC_PCNFSDPROG:
  286.     case RPC_PYRAMIDLOCKINGPROG:
  287.     case RPC_PYRAMIDSYS5:
  288.     case RPC_CADDS_IMAGE:
  289.     case RPC_ADT_RFLOCKPROG:
  290. #endif
  291.     default:
  292.         pkt_counters[PKT_OTHERRPC].pc_interval++;
  293.         pkt_counters[PKT_OTHERRPC].pc_total++;
  294.         break;
  295.     }
  296. }
  297.  
  298. /*
  299.  * rpc_replyfilter - count RPC reply packets.
  300.  */
  301. void
  302. rpc_replyfilter(data, length, src, dst, tstamp)
  303. register u_long src, dst;
  304. struct timeval *tstamp;
  305. register u_int length;
  306. register char *data;
  307. {
  308.     register struct rpc_msg *msg;
  309.  
  310.     msg = (struct rpc_msg *) data;
  311.  
  312.     pkt_counters[PKT_RPCAUTH].pc_interval++;
  313.     pkt_counters[PKT_RPCAUTH].pc_total++;
  314.     nfs_hash_reply(msg, dst, tstamp);
  315. }
  316.  
  317. /*
  318.  * nfs_filter - filter NFS packets.
  319.  */
  320. void
  321. nfs_filter(data, length, src, dst, tstamp)
  322. register u_long src, dst;
  323. struct timeval *tstamp;
  324. register u_int length;
  325. register char *data;
  326. {
  327.     u_int proc;
  328.     caddr_t args;
  329.     SVCXPRT *xprt;
  330.     struct rpc_msg msg;
  331.     union nfs_rfsargs nfs_rfsargs;
  332.     char cred_area[2*MAX_AUTH_BYTES];
  333.  
  334.     msg.rm_call.cb_cred.oa_base = cred_area;
  335.     msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
  336.  
  337.     /*
  338.      * Act as if we received this packet through RPC.
  339.      */
  340.     if (!udprpc_recv(data, length, &msg, &xprt))
  341.         return;
  342.  
  343.     /*
  344.      * Get the NFS procedure number.
  345.      */
  346.     proc = msg.rm_call.cb_proc;
  347.  
  348.     if (proc >= RFS_NPROC)
  349.         return;
  350.  
  351.     CountCallAuth(&msg);
  352.     nfs_hash_call(&msg, src, tstamp);
  353.  
  354.     /*
  355.      * Now decode the arguments to the procedure from
  356.      * XDR format.
  357.      */
  358.     args = (caddr_t) &nfs_rfsargs;
  359.     (void) bzero(args, nfs_procs[proc].nfs_argsz);
  360.  
  361.     if (!SVC_GETARGS(xprt, nfs_procs[proc].nfs_xdrargs, args))
  362.         return;
  363.  
  364.     prc_counters[prc_countmap[proc]].pr_total++;
  365.     prc_counters[prc_countmap[proc]].pr_interval++;
  366.  
  367.     CountSrc(src);
  368.  
  369.     /*
  370.      * Now count the packet in the appropriate file system's
  371.      * counters.
  372.      */
  373.     switch (proc) {
  374.     case RFS_NULL:
  375.         break;
  376.     case RFS_GETATTR:
  377.         nfs_count(&nfs_rfsargs.fhandle, proc);
  378.         break;
  379.     case RFS_SETATTR:
  380.         nfs_count(&nfs_rfsargs.nfssaargs.saa_fh, proc);
  381.         break;
  382.     case RFS_ROOT:
  383.         break;
  384.     case RFS_LOOKUP:
  385.         nfs_count(&nfs_rfsargs.nfsdiropargs.da_fhandle, proc);
  386.         break;
  387.     case RFS_READLINK:
  388.         nfs_count(&nfs_rfsargs.fhandle, proc);
  389.         break;
  390.     case RFS_READ:
  391.         nfs_count(&nfs_rfsargs.nfsreadargs.ra_fhandle, proc);
  392.         break;
  393.     case RFS_WRITECACHE:
  394.         break;
  395.     case RFS_WRITE:
  396.         nfs_count(&nfs_rfsargs.nfswriteargs.wa_fhandle, proc);
  397.         break;
  398.     case RFS_CREATE:
  399.         nfs_count(&nfs_rfsargs.nfscreatargs.ca_da.da_fhandle, proc);
  400.         break;
  401.     case RFS_REMOVE:
  402.         nfs_count(&nfs_rfsargs.nfsdiropargs.da_fhandle, proc);
  403.         break;
  404.     case RFS_RENAME:
  405.         nfs_count(&nfs_rfsargs.nfsrnmargs.rna_from.da_fhandle, proc);
  406.         break;
  407.     case RFS_LINK:
  408.         nfs_count(&nfs_rfsargs.nfslinkargs.la_from, proc);
  409.         break;
  410.     case RFS_SYMLINK:
  411.         nfs_count(&nfs_rfsargs.nfsslargs.sla_from.da_fhandle, proc);
  412.         break;
  413.     case RFS_MKDIR:
  414.         nfs_count(&nfs_rfsargs.nfscreatargs.ca_da.da_fhandle, proc);
  415.         break;
  416.     case RFS_RMDIR:
  417.         nfs_count(&nfs_rfsargs.nfsdiropargs.da_fhandle, proc);
  418.         break;
  419.     case RFS_READDIR:
  420.         nfs_count(&nfs_rfsargs.nfsrddirargs.rda_fh, proc);
  421.         break;
  422.     case RFS_STATFS:
  423.         nfs_count(&nfs_rfsargs.fhandle, proc);
  424.         break;
  425.     }
  426.  
  427.     /*
  428.      * Decide whether it's a read or write process.
  429.      */
  430.     switch (nfs_procs[proc].nfs_proctype) {
  431.     case NFS_READ:
  432.         pkt_counters[PKT_NFSREAD].pc_interval++;
  433.         pkt_counters[PKT_NFSREAD].pc_total++;
  434.         break;
  435.     case NFS_WRITE:
  436.         pkt_counters[PKT_NFSWRITE].pc_interval++;
  437.         pkt_counters[PKT_NFSWRITE].pc_total++;
  438.         break;
  439.     }
  440. }
  441.  
  442. /*
  443.  * nfs_count - count an NFS reference to a specific file system.
  444.  */
  445. void
  446. nfs_count(fh, proc)
  447. register fhandle_t *fh;
  448. int proc;
  449. {
  450.     long fsid;
  451.     register int i, match1, match2;
  452.  
  453.     /*
  454.      * Run through the NFS counters looking for the matching
  455.      * file system.
  456.      */
  457.     match1 = 0;
  458.  
  459.     for (i = 0; i < nnfscounters; i++) {
  460.         if (learnfs)
  461.             fsid = nfs_counters[i].nc_fsid;
  462.         else
  463.             fsid = (long) nfs_counters[i].nc_dev;
  464.  
  465.         /*
  466.          * Compare the device numbers.  Sun uses an
  467.          * fsid_t for the device number, which is an
  468.          * array of 2 longs.  The first long contains
  469.          * the device number.
  470.          */
  471.         match1 = !bcmp((char *) &(fh->fh_fsid), (char *) &fsid,
  472.             sizeof(long));
  473.  
  474.         /*
  475.          * Check server address.
  476.          */
  477.         if (allflag && match1)
  478.             match1 = (thisdst == nfs_counters[i].nc_ipaddr);
  479.  
  480.         if (match1) {
  481.             nfs_counters[i].nc_proc[proc]++;
  482.             nfs_counters[i].nc_interval++;
  483.             nfs_counters[i].nc_total++;
  484.             break;
  485.         }
  486.     }
  487.  
  488.     /*
  489.      * We don't know about this file system, but we can
  490.      * learn.
  491.      */
  492.     if (!match1 && learnfs && (nnfscounters < MAXEXPORT)) {
  493.         static char fsname[64], prefix[64];
  494.         long fsid;
  495.         int oldm;
  496.  
  497. #ifdef SVR4
  498.         sighold(SIGALRM);
  499. #else
  500.         oldm = sigblock(sigmask(SIGALRM));
  501. #endif
  502.                         /* no redisplay while unstable */
  503.  
  504.         i = nnfscounters++;
  505.  
  506.         bcopy((char *) &(fh->fh_fsid), (char *) &fsid, sizeof(long));
  507.  
  508.         nfs_counters[i].nc_fsid = fsid;
  509.         nfs_counters[i].nc_proc[proc]++;
  510.         nfs_counters[i].nc_interval++;
  511.         nfs_counters[i].nc_total++;
  512.  
  513.         /*
  514.          * See if server uses opposite byte order.
  515.          */
  516.         if ((fsid & 0xffff0000) && ((fsid & 0xffff) == 0))
  517.             fsid = ntohl(fsid);
  518.  
  519.         /*
  520.          * Some hosts use 32-bit values.
  521.          */
  522.         if (fsid & 0xffff0000) {
  523.             /*
  524.              * Try to intuit the byte order.
  525.              */
  526.             if (fsid & 0xff00) {
  527.               nfs_counters[i].nc_dev = makedev((fsid >> 8) & 0xff,
  528.                                (fsid >> 24) & 0xff);
  529.             }
  530.             else {
  531.               nfs_counters[i].nc_dev = makedev((fsid >> 16) & 0xff,
  532.                                fsid & 0xff);
  533.             }
  534.         }
  535.         else {
  536.             nfs_counters[i].nc_dev = makedev(major(fsid),
  537.                              minor(fsid));
  538.         }
  539.  
  540.         *prefix = 0;
  541.  
  542.         if (allflag) {
  543.             struct hostent *hp;
  544.  
  545.             nfs_counters[i].nc_ipaddr = thisdst;
  546.             hp = gethostbyaddr((char *) &thisdst, sizeof(thisdst),
  547.                        AF_INET);
  548.  
  549.             if (hp) {
  550.                 char *index();
  551.                 char *dotp;
  552.  
  553.                 sprintf(prefix, "%s", hp->h_name);
  554.  
  555.                 if ((dotp = index(prefix, '.')) != NULL)
  556.                     *dotp = 0;
  557.             }
  558.             else {
  559.                 struct in_addr ia;
  560.                 ia.s_addr = thisdst;
  561.                 sprintf(prefix, "%s", inet_ntoa(ia));
  562.             }
  563.         }
  564.  
  565.         sprintf(fsname, "%.12s(%d,%d)", prefix,
  566.             major(nfs_counters[i].nc_dev),
  567.             minor(nfs_counters[i].nc_dev));
  568.  
  569.         if (mapfile)
  570.             nfs_counters[i].nc_name = savestr(map_fs_name(fsname));
  571.         else
  572.             nfs_counters[i].nc_name = savestr(fsname);
  573.  
  574.         sort_nfs_counters();
  575. #ifdef SVR4
  576.         sigrelse(SIGALRM);
  577. #else
  578.         (void) sigsetmask(oldm);    /* permit redisplay */
  579. #endif
  580.     }
  581.  
  582.     if (filelist == NULL)
  583.         return;
  584.  
  585.     /*
  586.      * Run through the file counters looking for the matching
  587.      * file.
  588.      */
  589.     for (i = 0; i < nfilecounters; i++) {
  590.         fsid = (long) fil_counters[i].fc_dev;
  591.  
  592.         /*
  593.          * Compare device numbers and file numbers.  Sun
  594.          * uses an fsid_t for the device, which is an
  595.          * array of two longs.  They use an fid for the
  596.          * inode.  The inode number is the first part
  597.          * of this.
  598.          */
  599.         match1 = !bcmp((char *) &(fh->fh_fsid), (char *) &fsid,
  600.              sizeof(long));
  601.  
  602.         if (!match1)
  603.             continue;
  604.  
  605. #if defined(sun) && defined(sparc)
  606.         /*
  607.          * NOTE: this is dependent on the contents of the fh_data
  608.          *       part of the file handle.  This is correct for
  609.          *       SunOS 4.1 on SPARCs.
  610.          */
  611.         match2 = !bcmp((char *) &(fh->fh_data[2]),
  612.              (char *) &(fil_counters[i].fc_ino), sizeof(ino_t));
  613. #endif
  614.  
  615. #if defined(sun) && defined(mc68000)
  616.         /*
  617.          * Correct for SunOS 4.1 on Sun-3.
  618.          */
  619.         match2 = !bcmp((char *) &(fh->fh_data[0]),
  620.              (char *) &(fil_counters[i].fc_ino), sizeof(ino_t));
  621. #endif
  622.  
  623. #ifdef ultrix
  624.         /*
  625.          * Correct for Ultrix 4.x systems.
  626.          */
  627.         match2 = !bcmp((char *) fh->fh_fno,
  628.              (char *) &(fil_counters[i].fc_ino), sizeof(ino_t));
  629. #endif
  630.  
  631. #ifdef sgi
  632.         /*
  633.          * Correct for IRIX 3.3.
  634.          */
  635.         match2 = !bcmp((char *) &(fh->fh_data[4]),
  636.              (char *) &(fil_counters[i].fc_ino), sizeof(ino_t));
  637. #endif
  638.  
  639. #if !defined(sgi) && !defined(sun) && !defined(ultrix) 
  640.         /*
  641.          * This is a guess... it's probably correct for most
  642.          * SVR4 PC systems, anyway.
  643.          */
  644.         match2 = !bcmp((char *) &(fh->fh_data[0]),
  645.              (char *) &(fil_counters[i].fc_ino), sizeof(ino_t));
  646. #endif
  647.         
  648.         if (match2) {
  649.             fil_counters[i].fc_proc[proc]++;
  650.             fil_counters[i].fc_interval++;
  651.             fil_counters[i].fc_total++;
  652.             break;
  653.         }
  654.     }
  655. }
  656.  
  657. /*
  658.  * CountSrc uses a hash table to speed lookups.  Hash function
  659.  *    uses high and low octect of IP address, so as to be
  660.  *    fast and byte-order independent.  Table is organized
  661.  *    as a array of linked lists.
  662.  */
  663. #define    HASHSIZE    0x100
  664. #define    HASH(addr)    (((addr) & 0xFF) ^ (((addr) >> 24) & 0xFF))
  665.  
  666. ClientCounter *Addr_hashtable[HASHSIZE];    /* initially all NULL ptrs */
  667.  
  668. ClientCounter *cc_hint = clnt_counters;        /* one-element cache */
  669.  
  670. CountSrc(src)
  671. register u_long src;
  672. {
  673.     register ClientCounter *ccp;
  674.     int hcode = HASH(src);
  675.     
  676.     /* See if this is the same client as last time */
  677.     if (cc_hint->cl_ipaddr == src) {
  678.         cc_hint->cl_total++;
  679.         cc_hint->cl_interval++;
  680.         return;
  681.     }
  682.  
  683.     /* Search hash table */
  684.     ccp = Addr_hashtable[hcode];
  685.     while (ccp) {
  686.         if (ccp->cl_ipaddr == src) {
  687.         ccp->cl_total++;
  688.         ccp->cl_interval++;
  689.         cc_hint = ccp;
  690.         return;
  691.         }
  692.         ccp = ccp->cl_next;
  693.     }
  694.     
  695.     /* new client */
  696.     if (nclientcounters < MAXCLIENTS) {
  697.         struct hostent *hp;
  698.         static char clnt_name[64];
  699.         int oldm;
  700.         
  701. #ifdef SVR4
  702.         sighold(SIGALRM);
  703. #else
  704.         oldm = sigblock(sigmask(SIGALRM));
  705. #endif
  706.                         /* no redisplay while unstable */
  707.         
  708.         ccp = &(clnt_counters[nclientcounters]);
  709.         nclientcounters++;
  710.         
  711.         /* Add to hash table */
  712.         ccp->cl_next = Addr_hashtable[hcode];
  713.         Addr_hashtable[hcode] = ccp;
  714.  
  715.         /* Fill in new ClientCounter */
  716.         ccp->cl_ipaddr = src;
  717.         hp = gethostbyaddr((char *) &ccp->cl_ipaddr,
  718.                    sizeof(ccp->cl_ipaddr), AF_INET);
  719.         if (hp) {
  720.         char *index();
  721.         char *dotp;
  722.  
  723.         sprintf(clnt_name, "%s", hp->h_name);
  724.  
  725.         if ((dotp = index(clnt_name, '.')) != NULL)
  726.             *dotp = 0;
  727.         }
  728.         else {
  729.         struct in_addr ia;
  730.         ia.s_addr = ccp->cl_ipaddr;
  731.         sprintf(clnt_name, "%s", inet_ntoa(ia));
  732.         }
  733.  
  734.         ccp->cl_name = savestr(clnt_name);
  735.         ccp->cl_total = 1;
  736.         ccp->cl_interval = 1;
  737.         sort_clnt_counters();
  738. #ifdef SVR4
  739.          sigrelse(SIGALRM);
  740. #else
  741.         (void) sigsetmask(oldm);    /* permit redisplay */
  742. #endif
  743.     }
  744. }
  745.  
  746. /*
  747.  * Must be called after sorting the clnt_counters[] table
  748.  *    Should put busiest ones at front of list, but doesn't
  749.  */
  750. ClientHashRebuild()
  751. {
  752.     register int i;
  753.     register ClientCounter *ccp;
  754.     int hcode;
  755.  
  756.     bzero(Addr_hashtable, sizeof(Addr_hashtable));
  757.     
  758.     for (i = 0, ccp = clnt_counters; i < nclientcounters; i++, ccp++) {
  759.         hcode = HASH(ccp->cl_ipaddr);
  760.         ccp->cl_next = Addr_hashtable[hcode];
  761.         Addr_hashtable[hcode] = ccp;
  762.     }
  763. }
  764.  
  765. /*
  766.  * Code to count authentication instances.
  767.  */
  768. #define UIDOFFSET    100000        /* add to a non-uid so it won't
  769.                        conflict with uids        */
  770.  
  771. CountCallAuth(msg)
  772. struct rpc_msg *msg;
  773. {
  774.     int i, len, auth;
  775.     struct passwd *pw;
  776.     unsigned int *oauth;
  777.     static char user_name[16];
  778.  
  779.     auth = msg->ru.RM_cmb.cb_cred.oa_flavor;
  780.  
  781.     if (auth != AUTH_UNIX) {
  782.         auth += UIDOFFSET;
  783.     }
  784.     else {
  785.         /*
  786.          * Convert the opaque authorization into a uid.
  787.          * Should use the XDR decoders.
  788.          */
  789.         oauth = (unsigned int *) msg->ru.RM_cmb.cb_cred.oa_base;
  790.         len = ntohl(oauth[1]);
  791.  
  792.         if ((len % 4) != 0)
  793.             len = len + 4 - len % 4;
  794.  
  795.         auth = ntohl(oauth[2 + len / 4]);
  796.     }
  797.  
  798.     for (i=0; i < nauthcounters; i++) {
  799.         if (auth_counters[i].ac_uid == auth) {
  800.             auth_counters[i].ac_interval++;
  801.             auth_counters[i].ac_total++;
  802.             return;
  803.         }
  804.     }
  805.     
  806.     if (nauthcounters < MAXAUTHS) {
  807.         nauthcounters++;
  808.  
  809.         auth_counters[i].ac_uid = auth;
  810.         auth_counters[i].ac_total = 1;
  811.         auth_counters[i].ac_interval = 1;
  812.  
  813.         switch (auth) {
  814.         case AUTH_NULL + UIDOFFSET:
  815.             auth_counters[i].ac_name = "AUTH_NULL";
  816.             break;
  817.         case AUTH_UNIX + UIDOFFSET:
  818.             auth_counters[i].ac_name = "AUTH_UNIX";
  819.             break;
  820.         case AUTH_SHORT + UIDOFFSET:
  821.             auth_counters[i].ac_name = "AUTH_SHORT";
  822.             break;
  823.         case AUTH_DES + UIDOFFSET:
  824.             auth_counters[i].ac_name = "AUTH_DES";
  825.             break;
  826.         default:
  827.             if ((pw = getpwuid(auth)) != NULL)
  828.                 strcpy(user_name, pw->pw_name);
  829.             else
  830.                 sprintf(user_name, "#%d", auth);
  831.  
  832.             auth_counters[i].ac_name = savestr(user_name);
  833.             break;
  834.         }
  835.  
  836.         sort_auth_counters();
  837.     }
  838. }
  839.  
  840. /*
  841.  * Some code to look at response times.
  842.  */
  843. void
  844. nfs_hash_call(msg, client, tstamp)
  845. struct timeval *tstamp;
  846. struct rpc_msg *msg;
  847. u_long client;
  848. {
  849.     int i;
  850.  
  851.     if (tstamp == NULL)
  852.         return;
  853.  
  854.     for (i=0; i < NFSCALLHASHSIZE; i++) {
  855.         if (nfs_calls[i].used == 0) {
  856.             nfs_calls[i].used = 1;
  857.             nfs_calls[i].proc = msg->rm_call.cb_proc;
  858.             nfs_calls[i].client = client;
  859.             nfs_calls[i].xid = msg->rm_xid;
  860.             nfs_calls[i].time_sec = tstamp->tv_sec;
  861.             nfs_calls[i].time_usec = tstamp->tv_usec;
  862.             return;
  863.         }
  864.     }
  865. }
  866.  
  867. void
  868. nfs_hash_reply(msg, client, tstamp)
  869. struct timeval *tstamp;
  870. struct rpc_msg *msg;
  871. u_long client;
  872. {
  873.     int i;
  874.     double diff;
  875.     u_long proc;
  876.     u_long xid = ntohl(msg->rm_xid);
  877.  
  878.     if (tstamp == NULL)
  879.         return;
  880.  
  881.     for (i=0; i < NFSCALLHASHSIZE; i++) {
  882.         if (nfs_calls[i].used == 0)
  883.             continue;
  884.  
  885.         if (nfs_calls[i].client == client &&
  886.             nfs_calls[i].xid == xid) {
  887.             proc = prc_countmap[nfs_calls[i].proc];
  888.  
  889.             diff = ((tstamp->tv_sec - nfs_calls[i].time_sec) *
  890.                 1000000 +
  891.                 tstamp->tv_usec - nfs_calls[i].time_usec) /
  892.                 1000.0;
  893.  
  894.             prc_counters[proc].pr_complete++;
  895.             prc_counters[proc].pr_response += diff;
  896.             prc_counters[proc].pr_respsqr += diff * diff;
  897.  
  898.             if (diff > prc_counters[proc].pr_maxresp)
  899.                 prc_counters[proc].pr_maxresp = diff;
  900.  
  901.             nfs_calls[i].used = 0;
  902.             return;
  903.         }
  904.     }
  905. }
  906.